#
# This file is a part of the open-eBackup project.
# This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
# If a copy of the MPL was not distributed with this file, You can obtain one at
# http://mozilla.org/MPL/2.0/.
#
# Copyright (c) [2024] Huawei Technologies Co.,Ltd.
#
# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
# EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
# MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
#

import time

from common.common import output_result_file
from common.common_models import SubJobDetails, LogDetail, QueryPermissionModel, ActionResult
from common.const import BackupTypeEnum, SubJobStatusEnum, DBLogLevel, ExecuteResultEnum
from generaldb.saphana.backup.saphana_data_backup import SaphanaDataBackup
from generaldb.saphana.backup.saphana_log_backup import SaphanaLogBackup
from generaldb.saphana.backup.saphana_parse_backup_params import SaphanaParseBackupParam
from generaldb.saphana.comm.common_util import log
from generaldb.saphana.comm.saphana_const import SaphanaTaskLabel, SaphanaSubjobName
from generaldb.saphana.comm.saphana_common_function import CommonFuction


class BackupService:
    def __init__(self, pid, job_id, sub_job_id):
        self._pid = pid
        self._parse_params_obj = SaphanaParseBackupParam(pid, job_id, sub_job_id)
        self._backup_obj = None
        if self._parse_params_obj.get_backup_type() == BackupTypeEnum.LOG_BACKUP:
            self._backup_obj = SaphanaLogBackup(self._parse_params_obj, pid)
        else:
            self._backup_obj = SaphanaDataBackup(self._parse_params_obj, pid)

    @staticmethod
    def query_job_permission(pid, job_id, sub_job_id):
        log.info("Start to query job permission")
        parse_params_obj = SaphanaParseBackupParam(pid, job_id, sub_job_id)
        uid, gid = parse_params_obj.get_query_permission()
        if not uid or not gid:
            log.error(f"Fail to get job permission.{uid}, {gid}")
            return False
        permission_ret = QueryPermissionModel(user=uid, group=gid)
        try:
            output_result_file(pid, permission_ret.dict(by_alias=True))
        except Exception as err:
            log.error(f"Query permission fail for {err}")
            return False
        return True

    def allow_backup_in_local_node(self):
        ret = self._backup_obj.allow_backup_in_local_node()
        self._write_result(ret)
        return ret

    def check_backup_type(self):
        ret = self._backup_obj.check_backup_type()
        self._write_result(ret)
        return ret

    def exec_prerequisite_task(self):
        # 执行前置任务
        ret = self._backup_obj.exec_prerequisite_task()
        self._report_progress(ret, SaphanaTaskLabel.PREREQUISITE_FAIL_LABEL)

    def generate_subjob(self):
        # 拆分子任务
        subjob_array = self._backup_obj.generate_job()
        ret = True
        try:
            output_result_file(self._pid, subjob_array)
        except Exception as err:
            log.error(f"Fail to generate subjob for {err}")
            ret = False
        return ret

    def exec_subjob(self):
        # 执行子任务
        subjob_name = self._parse_params_obj.get_subjob_name()
        if subjob_name == SaphanaSubjobName.PREPARE:
            ret = self._backup_obj.exec_prepare_subtask()
            self._report_progress(ret, SaphanaTaskLabel.GENERATE_SUBJOB_FAIL_LABEL)
        elif subjob_name == SaphanaSubjobName.BACKUP:
            self._backup_obj.execute_backup_subtask()
        else:
            log.error(f"Unknown subjob {subjob_name}")
            self._write_result(False)
            return False
        return True

    def exec_post_job(self):
        # 执行后置任务
        self._backup_obj.exec_post_job()
        self._report_progress(True)

    def abort_backup(self):
        # 执行备份任务中止
        self._backup_obj.abort_backup()
        self._report_progress(True)

    def _report_progress(self, result: bool, error_label: str = ""):
        """
        功能：上报子任务结果
        参数：result：任务结果
             error_label：如果任务失败，上报的label
        """
        job_status = SubJobStatusEnum.COMPLETED if result else SubJobStatusEnum.FAILED
        if not result and error_label:
            log_detail = LogDetail(logInfo=error_label, logInfoParam=[],
                                   logTimestamp=int(time.time()), logLevel=DBLogLevel.ERROR,
                                   logDetail=self._backup_obj.get_error_code(),
                                   logDetailParam=self._backup_obj.get_error_params())
            progress_dict = SubJobDetails(taskId=self._parse_params_obj.get_maintask_id(),
                                          subTaskId=self._parse_params_obj.get_subtask_id(),
                                          taskStatus=job_status.value, progress=0, logDetail=[log_detail])
        else:
            progress_dict = SubJobDetails(taskId=self._parse_params_obj.get_maintask_id(),
                                          subTaskId=self._parse_params_obj.get_subtask_id(),
                                          taskStatus=job_status.value, progress=0)
        return CommonFuction.report_job_details(self._parse_params_obj.get_maintask_id(),
                                                progress_dict.dict(by_alias=True))

    def _write_result(self, ret):
        ret_code = ExecuteResultEnum.SUCCESS if ret else ExecuteResultEnum.INTERNAL_ERROR
        error_code = 0 if ret else self._backup_obj.get_error_code()
        output_result_file(self._pid, ActionResult(code=ret_code, bodyErr=error_code).dict(by_alias=True))
